package queries;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.URL;
import java.net.URLConnection;
import java.net.URLEncoder;

import javax.xml.parsers.ParserConfigurationException;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import org.xml.sax.SAXException;


/**
 * Query execution using Yahoo BOOS API
 * 
 * @author Vika vk2185
 * @author Antonio ak2765
 */
public final class YahooQueryExecutor implements QueryExecutor {

	private static final String BOSS_KEY = "9BvTPxLV34Gs8Dfbd2VVlOPh.sOaW_nyaj_niU7_uF2ELidyfsgP18u_gQ5K3Xz8W2yxnXiyu0Ly8EvgZp_MY2Dz41vSzOM-";

	/**
	 * Invokes Yahoo's BOSS API and read search results
	 * 
	 * @param connection a URLConnection
	 * @return returns Yahoo's BOSS response conde
	 * @throws IOException Failed invocation
	 */
	private String readBossResponse(URLConnection connection)
			throws IOException {
		String line;
		StringBuilder builder = new StringBuilder();
		BufferedReader reader = new BufferedReader(new InputStreamReader(
				connection.getInputStream()));
		while ((line = reader.readLine()) != null) {
			builder.append(line);
		}
		return builder.toString();
	}
	
	/**
	 * Executes the query parameter against the site and sample both passed as parameter.
	 * 
	 * @param site Target site
	 * @param query Query to execute
	 * @param sample collection of document to be filled for page summary and sampling
	 */
	public int executeQuery(String site, Query query, DocumentSample sample) {
		try {
			String encodedQuery = URLEncoder.encode(query.nativeStringQuery(),
					"UTF-8");

			URL url = new URL("http://boss.yahooapis.com/ysearch/web/v1/"
					+ encodedQuery + "?appid=" + BOSS_KEY + "&count=50&format=json&sites=" + site);

			URLConnection connection = url.openConnection();

			String bossResponseXml = readBossResponse(connection);

			return parseBossResponseXml(bossResponseXml, sample);
			
		} catch (Exception ex) {
			String errMsg = String.format("Failed query: %s", query.toString());
			throw new RuntimeException(errMsg, ex);
		}
	}

	/**
	 * Parse search results in XML format
	 * 
	 * @param bossResponseXml boss query
	 * @return Returns the number of sites related to the query passed as parameter
	 */
	private int parseBossResponseXml(String bossResponseXml, DocumentSample sample)
			throws ParserConfigurationException, SAXException, IOException,
			JSONException {
		
		JSONObject jobj = new JSONObject(bossResponseXml)
				.getJSONObject("ysearchresponse");

		String nextPage = jobj.has("nextpage") ? jobj.getString("nextpage")
				: null;
		sample.setNextResultUrl(nextPage);

		if (jobj.has("resultset_web")) {
			JSONArray res = jobj.getJSONArray("resultset_web");
			for (int i = 0; i < res.length() && i < 4; i++) {
				JSONObject thisResult = res.getJSONObject(i);

				queries.Document document = new queries.Document();

				document.setDescription(WebUtils.removeHtmlTags(thisResult
						.getString("abstract")));

				document.setTitle(WebUtils.removeHtmlTags(thisResult.getString("title")));

				document.setUrl(thisResult.getString("url"));

				sample.addDocument(document);
			}
			return res.length();
		}
		
		return 0;
	}

}
